#ifndef GLOBAL_H
#define GLOBAL_H

#include <qglobal.h>
#include <QRandomGenerator>




//修改!!!
#define _Format sprintf
#define _T QObject::tr
//#define _T QCoreApplication::tr

//#define CONFIG(X) config.configHash[#X].toInt()



/////////////////通用函数///////////////////////


//返回一个大随机数（4字节有符号）
quint32 intRand();
quint64 longRand();    //8字节

//n1~n2(不包括n2)随机数,n1和n2大小可以互换
quint32 Random(quint32 n1, quint32 n2);

//随机数命中率(m分之n)
qint32 RandTarget(quint32 n, quint32 m = 10000);

//n1到n2,取n个不同的数到arr,elementSize为元素大小
//使用hash
bool GetDifferentNumber(qint32 n1, qint32 n2, void* arr, int n, int elementSize);

//正态分布;
//参数为期望值(均值),标准差
//type>0,则是初始化种子; =0使用上次的种子产生; =-1:使用随机种子
//注意:返回的是double类型,如果需要整数,则可以:
//  1.直接int(),那么峰值有两个值(mean本身和mean-1),因为没有四舍五入,所以最好将方差带个 .5
//  2.用std::lround(number):峰值只有一个值.
//返回范围:
//mean +- standardDeviation:    68.2%
//mean +- 2*standardDeviation:  95.4%
//mean +- 3*standardDeviation:  99.7%
double lms_DefaultRandom(double mean, double standardDeviation, int type = 0);
double lms_DefaultRandom(double mean, double standardDeviation, double min, double max, int type = 0);




#include <QTextCodec>
//非ASCII码的个数
int nonASCIICount(QString str);



#include <QJsonDocument>
#include <QVariant>
QString JSon2String(QVariant data);
QVariant String2Json(QString json);

/////////////////Qt函数

//拷贝目录
bool copyDirectoryFiles(const QString &fromDir, const QString &toDir, bool coverFileIfExist);

#include <QFile>
//从assets拷贝文件和设置权限(安卓用),不覆盖
bool copyFileAndSetPermissions(const QString& filename, QFileDevice::Permissions permissionSpec);



//自定义 控制台输出
void customMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);




#include <QDebug>
#include <QDateTime>

inline void Warning(QString str)
{
    qWarning() << str;
}
inline void Debug(QString str)
{
    qDebug() << str;
}
inline void Critical(QString str)
{
    qCritical() << str;
}
inline void ShowTime()
{
    qDebug() << QDateTime::currentDateTime().time();
}



//////////////等待函数(不阻塞事件处理)//////////////////////

#include <QEventLoop>
void Wait(int msec, QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);

/*
    Wait1 和 Wait2 会让CPU飙升,且点了关闭按钮,也无法退出循环(除非到时)
*/
void Wait1(int msec);
void Wait2(int msec);






//
//Q_DECLARE_TR_FUNCTIONS(GameSlot)

//QTextCodec::setCodecForTr(QTextCodec::codecForName("System"));  //消除乱码

//class QPixmap;
//半透明显示图片
QPixmap Ltrans(QPixmap &pix1, int Alpha =255);

//显示一段内存(可用QByteArray代替!!)
void showHex(char *data,unsigned int length);






////////////////////事件过滤器///////////////////

#include <QObject>
#include <QEvent>

/*
 * 用法:
 * new EventFilter(要过滤的对象(可以为nullptr),parent);
 * 改写eventFilter函数,过滤watched的事件
*/

class EventFilter : public QObject
{
    Q_OBJECT
public:
    explicit EventFilter(QObject *watched = nullptr, QObject *parent = nullptr) :
           QObject(parent),
           m_watched(watched)
    {
    }
    virtual ~EventFilter(){}

    bool eventFilter(QObject *watched, QEvent *event)
    {
           if (m_watched == nullptr ||
                   watched == m_watched
              )
           {
                   if (event->type() == QEvent::MouseButtonDblClick)
                   {
                            qDebug() << "EventFilter";
                            return true;
                   }
           }
       return false;
    }

private:
    QObject *m_watched;
};





//////////////////配置文件////////////////////


#include <QHash>
#include <QFile>
#include <QDebug>
#include <QByteArray>

class Config
{
public:
    Config(QString strFileName = "Config.cfg")
    {
        configFile.setFileName(strFileName);
        //readConfigFile();
    }
    int readConfigFile(QVariantMap &mapConfig)
    {
        if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            qWarning() << QString("[!WARNING]Open file %1 failed！").arg(configFile.fileName());
            return -1;
        }
        else
        {
            while (!configFile.atEnd())
            {
                QString str;
                int n;

                str = QString::fromLatin1(configFile.readLine());

                if(str.indexOf("#") == 0)
                    continue;
                if((n = str.indexOf("=")) == -1)
                    continue;

                //qDebug() << n << str.left(n).trimmed() << "====" << str.mid(n+1).trimmed();
                mapConfig[str.left(n).trimmed()] = str.mid(n+1).trimmed();
                //qDebug()<<configHash[str.left(n).trimmed()];
            }
            configFile.close();
        }
        return 0;
    }

public:
    QFile configFile;
};



////////////////////随机数///////////////////
inline int lmsSrand(int type)
{
    static int s = QDateTime::currentDateTime().time().msec();
    static QRandomGenerator rg;
    switch (type) {
    case -1:    //每次都随机
        type = QDateTime::currentDateTime().time().msec();
        break;
    case 0:     //固定一个随机种子(可以调试)
        type = s;
        break;
    default:    //(具体随机种子)
        //type = config.configHash["RAND"].toInt();
        break;
    }

    //::qsrand(type);
    rg.seed(type);

    return type;
    //qDebug()<<config.configHash["RAND"].toInt();
}









////////////////////生产者模式类///////////////////

#include <QSemaphore>
#include <QQueue>
#include <QMutex>

//游戏数据基类,要在游戏中再次继承,生产消费者模型中使用!
struct __ProducerData
{
    explicit __ProducerData();
    virtual ~__ProducerData();

public:
    int type;       //数据类型
    void *sender;   //发送者,某个客户(_ClientInfo)

public:
    virtual void Release();
};

//生产者/消费者模型
class ProducerModel
{
public:
    explicit ProducerModel();
    virtual ~ProducerModel();

public:

    void init()
    {
        //释放信号量
        int t = available();
        if(t > 0)
            usingNetDataSemaphore(t);
        resetDataList();
        qDebug() << "[ProducerModel]清空生产者对象:" << available()
                 << m_listData.count();
    }

    //安全放入Data(本线程或使用者线程)
    void safeIn(__ProducerData *pData)
    {
        getDataList()->append(pData);
        comingNetDataSemaphore();
        releaseDataList();
    }

    //安全拿出Data(使用者线程)
    __ProducerData *safeOut()
    {

        /*方法1:
        QList<_GameData*> *pDataList = getDataList();
        if(pDataList->count() == 0)
        {
            releaseDataList();
            Debug(_T("等待中..."));
            //RefreshUI();
            WaitForNet();
            pDataList = getDataList();
        }
        m_mutexUserAction.tryLock();


        //方法2:
        QList<_GameData*> *pDataList;
        while(1)
        {
            pDataList = getDataList();
            if(pDataList->count() == 0)
            {
                releaseDataList();
                Debug(_T("等待中..."));
                //RefreshUI();
                WaitForNet();
                if(gameStatus() != Game_Status_Continue)
                    break;
            }
            else
                break;
        }
        if(gameStatus() != Game_Status_Continue)
            return nullptr;
        */


        /*方法3:
        QList<__ProducerData*> *pListData;

        pListData = getDataList();
        qDebug() << "等待中1...";
        while(!m_semaphoreData.tryAcquire())
        {
            releaseDataList();
            qDebug() << "等待中2...";
            usingNetDataSemaphore();

            //if(gameStatus() != Game_Status_Continue)
            //    return nullptr;

            pListData = getDataList();
            qDebug() << "thread:get!";
            break;
            //RefreshUI();
            //WaitForNet();
            //if(gameStatus() != Game_Status_Continue)
            //    break;
        }*/



        //!!!方法4:
        QList<__ProducerData*> *pListData = nullptr;

        qDebug() << "等待中1...";
        usingNetDataSemaphore();
        qDebug() << "等待中2...";
        pListData = getDataList();
        qDebug() << "thread:get!";



        /*
        //qDebug() << "m_mutexData.tryLock():" << m_mutexData.tryLock() << ::GetCurrentThreadId() << QThread::currentThreadId();;

        qDebug() << "游戏队列中有数据:" << pListData->count();
        QList<_GameData*>::iterator ii;
        for(ii = pListData->begin(); ii != pListData->end(); ii++)
        {
            qDebug() << "数据:" << (*ii)->type;
        }*/

        __ProducerData *pData = nullptr;
        if(!pListData->isEmpty())
            pData = pListData->takeFirst();

        releaseDataList();

        return pData;
    }

    //通知semaphore入或出
    void comingNetDataSemaphore(int n = 1)
    {
        m_semaphoreData.release(n);
        qDebug() << "增加一个Semaphore";
    }
    void usingNetDataSemaphore(int n = 1)
    {
        m_semaphoreData.acquire(n);
        qDebug() << "减少一个Semaphore";
    }

    int available()
    {
        return m_semaphoreData.available();
    }

protected:
    QQueue<__ProducerData*> m_listData; //游戏数据(传输)
    QMutex m_mutexData;             //锁m_listData

    QSemaphore m_semaphoreData;     //信号量，计数


    //锁住并返回
    QList<__ProducerData*> *getDataList()
    {
        //Debug_Leamus(QString("m_mutexData.lock()"));
        qDebug()<<"m_mutexData lock0!!!";
        m_mutexData.lock();
        qDebug()<<"m_mutexData lock1!!!";
        return &m_listData;
    }

    //释放datalist
    void releaseDataList()
    {
        qDebug()<<"m_mutexData trylock unlock0!!!";
        //Debug_Leamus("m_mutexData.unlock()");
        //m_mutexData.tryLock();
        m_mutexData.unlock();
        qDebug()<<"m_mutexData trylock unlock1!!!";
    }

    //清除DataList(本线程或使用者线程)
    void resetDataList()
    {
        getDataList();
        /*while(!list->isEmpty())
            delete list->takeFirst();*/
        qDeleteAll(m_listData);
        m_listData.clear();

        releaseDataList();
    }

    /*
    #include <QEventLoop>

    _GameData* Game::WaitingForOthers()
    {
        QEventLoop eventLoop;
        eventLoop.exec();
    }
    */

};



////////////////////池类///////////////////
//_TData必须有 _pool_init 和 _pool_release 函数用来初始化和释放操作
/*池的使用注意事项：
 * 池有一个基节点（也就是模板的_TData）和多个扩展节点；所有节点都可以声明一个ExtraData指针和pool_init()、pool_release()成员函数；
 *   基节点：可以声明set、Unset、init、release回调函数指针，这四个指针在最外层节点被定义和赋值。
 *     因为回调函数是从池发起的的getOneEmpty和releaseOneUsing发起的，然后调用了基节点的set、unset、init和release指针；
 *   其他扩展节点：且可以有ExtraData和pool_init()、pool_release()和set()、unset()、init()、release()回调函数定义：
 *     set回调函数用来调用 n-1节点的set函数 和 new一个节点，unset用来调用 n-1节点的unset函数 和释放一个节点；init用来调用本层节点的pool_init和上一个节点的pool_init()；release用来调用本层节点的pool_release和上一个节点的pool_release()；
 *       上面的调用除了根节点的回调函数都是是池调用的，其他节点的回调函数都必须出现在n+1节点的回调函数中（形成链条）。
 * set和unset就是调用上一层节点的set（创建节点）函数，并创建当前节点给上一层ExtraData使用的。
 * 链条形式(set举例)：
 *   getOneEmpty->基节点set指针->节点n的set回调->节点n-1的set回调->...->节点1的set回调。
 * 数据链条分布：
 *   池->基节点(ExtraData)->节点1(ExtraData)->...->节点n
 * 节点n的回调函数形式：
 *   set()
 *   {
 *     上层节点指针 = 上层节点set;
 *     上层节点指针->ExtraData = new 本层节点;
 *   }
 *   init(void *pExtraData) //pExtraData为基节点的ExtraData指针,所以只能传递到节点1
 *   {
 *     是否指针为空;
 *     //注意顺序：set和init是上层节点在先，unset和release是上层节点在后!!!
 *     上层节点init(pExtraData);
 *     pExtraData->pExtraData->...->_pool_init();   //一直追溯到本层节点
 *   }
 *
 * 其他注意:如果是单线程,则不用加锁;
 * 如果是多线程,则必须加锁,且注意 Data 的构造函数 、Init、Release的线程!!!
*/
#include <QMap>
template< class _TData >
class _LMS_Pool
{
public:
    class _Data: public _TData
    {
    //函数
    public:
        explicit _Data()//:m_Position(nullptr)
        //    ,pExtraData(nullptr)
        {
            m_bNew = true;

            m_bInit = false;
            m_bRelease = true;
            //_init();      //这里不需要init，getoneempty时调用
        }
        virtual ~_Data()
        {
            _release();
            //m_bInit = false;
            //m_bRelease = true;
        }


        //每次 调出 时的初始化或 调入时的 释放
        virtual void _init()
        {
            //_TData::_showInfo();
            if(!m_bInit)
            {
                m_bInit = true;
                m_bRelease = false;
                //pos = nullptr;
                _TData::_pool_init();
            }
        }
        virtual void _release()
        {
            //_TData::_showInfo();
            if(!m_bRelease)
            {
                m_bInit = false;
                m_bRelease = true;
                //pos = nullptr;
                _TData::_pool_release();
            }
        }


        //设置为 旧节点(不是新new的)，返回原来值
        virtual bool SetNewNode(bool bNew = false)
        {
            bool b = m_bNew;
            m_bNew = bNew;
            return b;
        }
        //是否为new节点（有些情况，上下文根据是否为新节点然后进行操作，比如连接信号，设置成员变量）
        virtual bool IsNewNode()
        {
            return m_bNew;
        }
    public:
        //POSITION m_Position;    //在列表中的位置
        //void *pExtraData;

        //保证初始化一次和释放一次
        bool m_bInit;
        bool m_bRelease;

        bool m_bNew;    //是否是new出来的节点(有些地方可能需要初始化一下)
    };

public:
    explicit _LMS_Pool()
    {
        /*
        if((m_hMutexListUsing = ::CreateMutex(nullptr, FALSE, "")) == nullptr)
        {
            TRACE(_T("[IOCPDEBUG]创建MutexUsing失败，错误代码: %d!"), WSAGetLastError());
        }
        if((m_hMutexListEmpty = ::CreateMutex(nullptr, FALSE, "")) == nullptr)
        {
            TRACE(_T("[IOCPDEBUG]创建MutexEmpty失败，错误代码: %d!"), WSAGetLastError());
        }

        InitializeCriticalSection(&m_csListUsing);
        InitializeCriticalSection(&m_csListEmpty);
        */

        m_bUsingLocker = true;
        m_bEmptyLocker = true;

        m_nReserveCount = 0;

        return;
    }
    virtual ~_LMS_Pool()
    {
        clearEmptyList();
        clearUsing();

        //RELEASE_HANDLE(m_hMutexListUsing);
        //RELEASE_HANDLE(m_hMutexListEmpty);
    }

//其他函数
public:
    //得到一个空的Data,并加入到Using中,返回此Data
    //会查找EmptyList,如果没有则新建
    _TData* getOneEmpty()
    {
        lockEmpty();
        //WaitForSingleObject(m_hMutexListEmpty, INFINITE);
        _Data* d = nullptr;

        //补足最低数
        while(m_listEmpty.count() < m_nReserveCount + 1)
        {
            d = new _Data;
            if(nullptr != d)
                m_listEmpty.append(d);
            else
                qWarning() << "[!WARNING]getOneEmpty:new _Data is nullptr";
        }

        if(m_listEmpty.count() == 0)
        {
            unlockEmpty();
            //ReleaseMutex(m_hMutexListEmpty);
            d = new _Data;
            if(nullptr == d)
            {
                qWarning() << "[!WARNING]getOneEmpty:new _Data is nullptr";
                return nullptr;
            }
        }
        else
        {
            d = (_Data*)m_listEmpty.takeFirst();
            unlockEmpty();
            //ReleaseMutex(m_hMutexListEmpty);
        }

        d->_init();

        lockUsing();
        //WaitForSingleObject(m_hMutexListUsing, INFINITE);
        //d->pos =
        m_mapUsing.insert(d, d);
        unlockUsing();
        //ReleaseMutex(m_hMutexListUsing);
        return d;
    }

    //释放一个UsingData,并加入到EmptyList中
    //返回UsingData剩余个数
    //错误返回-1
    int releaseOneUsing(_TData *td)
    {
        if(nullptr == td)
        {
            qWarning() << "[!WARNING]releaseOneUsing: nullptr";
            return -1;
        }

        _Data* d = (_Data*)td;

        lockUsing();
        //WaitForSingleObject(m_hMutexListUsing, INFINITE);
        int count = m_mapUsing.remove(d);
        int n = m_mapUsing.count();
        unlockUsing();
        //ReleaseMutex(m_hMutexListUsing);
        //if(d==nullptr)return -1;

        if(count == 1)
            d->_release();
        else
            qWarning() << "[!WARNING]releaseOneUsing:" << count;
        //d->pExtraData = nullptr;

        lockEmpty();
        //WaitForSingleObject(m_hMutexListEmpty, INFINITE);

        m_listEmpty.append(d);
        unlockEmpty();
        //ReleaseMutex(m_hMutexListEmpty);
        return n;
    }
/*
    //释放一个列表到EmptyList,其他同上
    int releaseListUsing(QList<_TData*> &tlist)
    {
        POSITION pos;
        pos = tlist.GetHeadPosition();
        EnterCriticalSection(&m_csListUsing);
        //WaitForSingleObject(m_hMutexListUsing, INFINITE);
        while(pos != nullptr)
        {
            m_listUsing.RemoveAt(((_Data*)tlist.GetNext(pos))->pos);
        }
        int n = m_listUsing.GetCount();
        LeaveCriticalSection(&m_csListUsing);
        //ReleaseMutex(m_hMutexListUsing);


        pos = tlist.GetHeadPosition();
        EnterCriticalSection(&m_csListEmpty);
        //WaitForSingleObject(m_hMutexListEmpty, INFINITE);
        while(pos != nullptr)
        {
            _Data* d = (_Data*)tlist.GetNext(pos);
            d->_release();
            //d->pExtraData = nullptr;
            m_listEmpty.AddTail(d);
        }

        LeaveCriticalSection(&m_csListEmpty);
        //ReleaseMutex(m_hMutexListEmpty);
        return n;


        / *
        int n = 0;
        POSITION pos = tlist.GetHeadPosition();

        while(pos != nullptr)
        {
            releaseOneUsing(tlist.GetNext(pos));
            n++;
        }
        return n;
        * /
    }*/

    //清空EmptyList
    void clearEmptyList()
    {
        lockEmpty();
        //WaitForSingleObject(m_hMutexListEmpty, INFINITE);

        qDeleteAll(m_listEmpty);
        m_listEmpty.clear();

        unlockEmpty();
        //ReleaseMutex(m_hMutexListEmpty);
    }

    //清空UsingList
    void clearUsing()
    {
        lockUsing();
        //WaitForSingleObject(m_hMutexListUsing, INFINITE);

        //qDeleteAll(m_mapUsing);
        typename QMap<_TData*, _TData*>::const_iterator ii;
        for (ii = m_mapUsing.constBegin(); ii != m_mapUsing.constEnd(); ++ii)
        {
            delete (_Data*)(ii.value());
        }
        m_mapUsing.clear();
        unlockUsing();
        //ReleaseMutex(m_hMutexListUsing);
    }

    int getEmptyCount()
    {
        lockEmpty();
        int count = m_listEmpty.count();
        unlockEmpty();
        return count;
    }

    int getUsingCount()
    {
        lockUsing();
        int count = m_mapUsing.count();
        unlockUsing();
        return count;
    }


    void lockUsing()
    {
        if(m_bUsingLocker)
            m_mutexUsing.lock();
    }

    void unlockUsing()
    {
        if(m_bUsingLocker)
            m_mutexUsing.unlock();
    }

    void lockEmpty()
    {
        if(m_bEmptyLocker)
            m_mutexListEmpty.lock();
    }

    void unlockEmpty()
    {
        if(m_bEmptyLocker)
            m_mutexListEmpty.unlock();
    }


public:
    //节点列表(使用 和 空)
    //QList<_Data*> m_listUsing;
    QMap<_TData*, _TData*> m_mapUsing;
    QList<_TData*> m_listEmpty;

    //HANDLE m_hMutexListUsing;
    //HANDLE m_hMutexListEmpty;
    //两个锁
    QMutex  m_mutexUsing;
    QMutex  m_mutexListEmpty;

    //是否需要锁,默认开启(如果是一个线程,则不用加锁)
    bool    m_bUsingLocker;
    bool    m_bEmptyLocker;

    int     m_nReserveCount;    //最少预留多少个

};




//新线程 耗时任务（数据库操作等）
//自身创建1个线程m_pThread并运行时间循环，也将自身放入 m_pThread 中，并进行管理
//使用 destroy 来结束和释放(其他线程可以调用)
//所以必须要用new来创建，且不能有parent
//注意：构造函数在创建本对象的线程中运行，而其他函数都是m_pThread中运行的（_init、_release、析构函数）
//使用Invoke来调用函数去Work耗时任务，类自身提供了runCallBack任务来回调耗时函数，运行结束后发送s_RunCallBackFinished信号
//m_pThread是主线程的对象，所以连接槽时切要注意
class LongTask : public QObject
{
    Q_OBJECT
public:
    explicit LongTask(/*QObject *parent = nullptr*/);
    virtual ~LongTask();


signals:
    void s_RunCallBackFinished(QVariant ret, int id);


public:
    //外部 或 自己调用，销毁对象，尽量别用delete（用了也无妨）
    Q_INVOKABLE int destroy();
    QThread *thread();


//子类可以继承，用来初始化和释放资源
protected slots:
    //线程中自动进行初始化(线程start后)
    virtual int _init();
    //外部调用destroy后线程中自动调用
    virtual int _release();


private:
    //通用型线程回调函数,必须用QMeta::invokeMethod方式调用才能在线程中执行
    //外部用QMeta::invokeMethod可以访问到私有函数，但不知派生类能不能调用到（按理说应该不行，可以将private改为protected）
    Q_INVOKABLE void runCallBack(void *fn, QVariant vParam, int id)
    {
        QVariant (*pCallBackFuntion)(QVariant,int) = (QVariant(*)(QVariant,int))fn;
        //int (*)(void*,void*,int) pCallBackFuntion2 = (int(*)(void*,void*,int))funtion;
        QVariant ret = pCallBackFuntion(vParam, id);
        emit s_RunCallBackFinished(ret, id);
        //return ret;
    }
    //用法：
    /*
    //1.定义对象LongTask对象和QVariant参数，id表示事件id，供结果处理函数判断处理
    LongTask *pLongTask = new LongTask;      //自动创建线程并把自己放在线程中
    QVariant v = "hello";
    QMetaObject::invokeMethod(pLongTask,"runCallBack"    //线程中执行这个函数，函数会回调testFunc
                              ,Qt::AutoConnection
                              //,Q_RETURN_ARG(QVariant, v)
                              ,Q_ARG(void*, (void*)callbackFunction)
                              ,Q_ARG(QVariant, v)
                              ,Q_ARG(int, 999)
                              );
    //2.定义回调函数执行完毕后接受的槽函数（参数为运行结果ret和事件id）
    connect(pLongTask, &LongTask::s_RunCallBackFinished, this, [=](QVariant ret, int id)
    {
        qDebug() << "finish thread:" << QThread::currentThreadId() << ret << id;
    });

    //3.定义线程需要调用的回调函数
    QVariant callbackFunction(QVariant v, int id)  //v和id是步骤1传递的
    {
        qDebug() << "worker thread:" << QThread::currentThreadId() << v << id;
        return 666;     //返回值会传到步骤2的结果处理函数中
    }
*/


public slots:



protected:
    QThread *m_pThread;
    bool m_bDestroyed;
};


/*
//实现方式2：
//新线程 耗时任务（数据库操作等）
//将自身放入 m_pThread 中，并进行管理
//使用 quit来结束和释放
//!!!有问题：finish后，接受不到deleteLater
#include <QThread>
class WorkerThread : public QThread
{
    Q_OBJECT
public:
    explicit WorkerThread();//QObject *parent = nullptr);
    virtual ~WorkerThread();

signals:

public:
    int init();
    int release();

public slots:

};
*/



//将qDebug()等函数写入文件的类,且运行在单独的一个线程
//可将5个文件路径和名称设置为相同或不同,如果为空则不记录
//目前最好的建立方式是在main中,指针在global处(方便MessageHaddle调用)
//程序运行结束前调用destroy即可.
Q_DECLARE_METATYPE(QIODevice::OpenMode)
class FileWriteTask: public LongTask
{
    Q_OBJECT

public:
    explicit FileWriteTask()
    {}


//必须用QMeta::invokeMethod方式调用才能在线程中执行
private:
    Q_INVOKABLE void WriteDataToFile(QIODevice::OpenMode mode, const QString filename, const QByteArray baData);
    Q_INVOKABLE void WriteTextToFile(QIODevice::OpenMode mode, const QString filename, const QString text);

};


//实现方法2，直接用回调函数
//使用方法：
/*
FileWriteTask2 *p = new FileWriteTask2;
p->WriteTextToFile(QIODevice::WriteOnly | QIODevice::Append, "Hello.txt", "Pleafles");
*/
class FileWriteTask2
{
public:
    explicit FileWriteTask2()
    {
        m_LongTask = new LongTask;
    }
    virtual ~FileWriteTask2()
    {
        m_LongTask->destroy();
    }


public:
    void WriteDataToFile(QIODevice::OpenMode mode, const QString filename, const QByteArray baData);
    void WriteTextToFile(QIODevice::OpenMode mode, const QString filename, const QString text);


private:
    //id为1：写ByteArray；为2：写QString
    //必须用QMeta::invokeMethod方式调用才能在线程中执行
    static QVariant WriteToFileCallback(QVariant v, int id);  //v和id是步骤1传递的



public:
    LongTask *m_LongTask;
};




#endif // GLOBAL_H
